#region Copyright

// The contents of this file are subject to the Mozilla Public License
//  Version 1.1 (the "License"); you may not use this file except in compliance
//  with the License. You may obtain a copy of the License at
//  
//  http://www.mozilla.org/MPL/
//  
//  Software distributed under the License is distributed on an "AS IS"
//  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//  License for the specific language governing rights and limitations under 
//  the License.
//  
//  The Initial Developer of the Original Code is Robert Smyth.
//  Portions created by Robert Smyth are Copyright (C) 2008.
//  
//  All Rights Reserved.

#endregion

using System;
using System.IO;
using System.Xml;
using NUnitGridThreadRunner.Alchemi.Metrics;


namespace NUnit.Extensions.NUnitGridRunner.Metrics
{
    public class SuiteMetrics : ISuiteMetrics
    {
        private readonly TimeSpan defaultExpectedRunTime = TimeSpan.FromSeconds(5);
        private readonly FixtureMetricsCollection fixtures;
        private readonly string testResultsFolder;
        private readonly TimeSpan totalTime;
        private int newFixturesCount;

        public SuiteMetrics(FixtureMetricsCollection fixtures, TimeSpan totalTime, string testResultsFolder)
        {
            this.fixtures = fixtures;
            this.totalTime = totalTime;
            this.testResultsFolder = testResultsFolder;
        }

        public IFixtureMetrics[] Fixtures
        {
            get { return fixtures.ToArray(); }
        }

        public TimeSpan TotalTime
        {
            get { return totalTime; }
        }

        public int NewFixturesCount
        {
            get { return newFixturesCount; }
        }

        public IFixtureMetrics GetMetrics(string testFixture)
        {
            IFixtureMetrics fixtureMetrics = null;

            if (fixtures.Contains(testFixture))
            {
                fixtureMetrics = fixtures[testFixture];
            }
            else
            {
                string fixtureResultsFile = Path.Combine(testResultsFolder,
                                                         string.Format("{0}.TestResults.xml", testFixture));
                if (File.Exists(fixtureResultsFile))
                {
                    string xmlText;
                    using (var streamReader = new StreamReader(fixtureResultsFile))
                    {
                        xmlText = streamReader.ReadToEnd();
                    }

                    var document = new XmlDocument();
                    try
                    {
                        document.LoadXml(xmlText);

                        XmlNode node = document.SelectSingleNode("/test-results/test-suite");
                        TimeSpan lastRunTime = TimeSpan.FromSeconds(float.Parse(node.Attributes["time"].Value));

                        fixtureMetrics = new FixtureMetrics("Unknown", testFixture, lastRunTime);
                    }
                    catch (Exception exception)
                    {
                        Console.Error.WriteLine("Error reading '{0}'. Possibly corrupt.\nException {1}",
                                                fixtureResultsFile,
                                                exception.Message);
                        fixtureMetrics = null;
                    }
                }

                if (fixtureMetrics == null)
                {
                    newFixturesCount = NewFixturesCount + 1;
                    fixtureMetrics = new FixtureMetrics("Default", testFixture, defaultExpectedRunTime);
                }
            }

            return fixtureMetrics;
        }

        public float GetExpectedTime(string[] fixtureNames)
        {
            double seconds = 0.0;
            foreach (string fixtureName in fixtureNames)
            {
                IFixtureMetrics metrics = GetMetrics(fixtureName);
                seconds += metrics.RunTime.TotalSeconds;
            }
            return (float) seconds;
        }
    }
}